package com.gavin.plugin.database;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Properties;

//import org.apache.commons.dbcp.BasicDataSource;
//import org.apache.log4j.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gavin.model.DataType;
import com.gavin.model.JObject;
import com.gavin.model.Model;
import com.gavin.model.Models;
import com.gavin.model.Result;
import com.gavin.plugin.database.help.DatabaseUtils;
import com.gavin.plugin.database.help.RecordUtils;
import com.gavin.plugin.database.help.ValueUtils;
import com.gavin.plugin.database.optimize.TransLog;
import com.gavin.plugin.database.optimize.parse.AnalyzedSQL;
import com.gavin.security.AES;
import com.gavin.security.MD5;
import com.gavin.utils.DBUtils;
import com.gavin.utils.Utility;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

/**
 * ------------------------------ 数据引擎 ------------------------------
 * 
 * @author wdm（l311576@sina.com） @date 2018年6月25日
 * @version 1.0
 */
public class DataEngine {
	private static Logger logger = LoggerFactory.getLogger(DataEngine.class);

	// 定义数据库驱动程序名称
	// private static final String DRIVER_SQLSERVER="net.sourceforge.jtds.jdbc.Driver";
	// private static final String DRIVER_ORACLE ="oracle.jdbc.driver.OracleDriver";
	// private static final String DRIVER_DB2 ="com.ibm.db2.jdbc.app.DB2Driver";
	// private static final String DRIVER_MYSQL ="com.mysql.jdbc.Driver";

	// 数据库连接池
	// private BasicDataSource ds;
	private HikariDataSource ds;

	private String strDriver;
	private String strURI;
	private Properties properties;
	private String strUserName;
	private String strPassword;
	private int nMinConnectionCount;
	private int nMaxConnectionCount;
	private int nTimeout;
	private int nMaxIdleConnectionCount;
	private int nMaxWaitTimeForIdleConnection;
	private int nMaxConnIdleTimeMS;
	private int nCheckIdleIntervalMS;
	private boolean bRemoveAbandoned;
	private AES aes;
	private int nCheckIdleConnCountOnce;
	private int nLoadLevel;
	private String dataGroupId = "DataSource";
	
	public DataEngine() {
		this.strDriver = "";
		this.strURI = "";
		this.properties = null;
		this.ds = null;
		this.strUserName = "";
		this.strPassword = "";
		this.nMinConnectionCount = 1;
		this.nMaxConnectionCount = 3;
		this.nTimeout = 60;
		this.nMaxIdleConnectionCount = 10;
		this.nMaxWaitTimeForIdleConnection = 10000;
		this.nMaxConnIdleTimeMS = 600000;
		this.nCheckIdleIntervalMS = 60000;
		this.nCheckIdleConnCountOnce = 1;
		this.bRemoveAbandoned = false;
	}
	
	/**
	 * 执行sql
	 * @param conn
	 * @param sourceSQL
	 * @param modelRequest
	 * @param formatSQL
	 * @return
	 * @throws SQLException
	 */
	public PreparedStatement prepareStatement(Connection conn, String sourceSQL, Model modelRequest, StringBuilder formatSQL) throws SQLException {
		PreparedStatement ps = null;
		
		// 分析原始SQL语句，得到其中的变量
		AnalyzedSQL analyzedSQL = AnalyzedSQL.analyzeSourceSQL(sourceSQL, modelRequest);
		if (analyzedSQL == null) {
			throw new SQLException("Analyze source SQL exception: " + sourceSQL);
		}
		sourceSQL = analyzedSQL.getFormatSQL();
		
		// 准备JDBC语句
		try {
			if (ps == null) {
				ps = conn.prepareStatement(analyzedSQL.getSourceSQL());
			}
			
			int nParaCount = analyzedSQL.getParaNames().size();
			for (int i = 0; i < nParaCount; i++) {
				String strParaName = analyzedSQL.getParaNames().get(i);
				if (strParaName == null) {
					ps.setObject(i + 1, null);
					continue;
				}
				
				String strEncoder = null;
				if (strParaName.startsWith("es:") == true || strParaName.startsWith("ef:") == true) {// 字段需要加密,es:对称加密，ef:指纹加密
					strEncoder = strParaName.substring(1, 2);
					strParaName = strParaName.substring(3);
				} else if (strParaName.startsWith("esu:") == true || strParaName.startsWith("efu:") == true || strParaName.startsWith("esl:") == true || strParaName.startsWith("efl:") == true) {// 字段需要转换大小写后再加密,es:对称加密，ef:指纹加密
					strEncoder = strParaName.substring(1, 3);
					strParaName = strParaName.substring(4);
				}
				JObject object = null;
				Object objValue = null;
				object = ValueUtils.getObject(modelRequest, strParaName);
				if (object == null) {
					ps.setNull(i + 1, Types.VARCHAR);
					continue;
				}
				
				objValue = object.getValue();
				DataType nType = object.getType();
				switch (nType) {
				case _byte:
				case _short:
				case _int:
				case _long:
				case _float:
				case _double: {
					ps.setObject(i + 1, objValue);
					break;
				}
				case _string: {
					String strValue = (String) objValue;
					if (strEncoder != null) {
						if (strEncoder.equalsIgnoreCase("s")) {
							strValue = this.aes.encode(strValue);
						} else if (strEncoder.equalsIgnoreCase("f")) {
							strValue = MD5.encode(strValue);
						} else if (strEncoder.equalsIgnoreCase("sl")) {
							strValue = this.aes.encode(strValue.toLowerCase());
						} else if (strEncoder.equalsIgnoreCase("su")) {
							strValue = this.aes.encode(strValue.toUpperCase());
						} else if (strEncoder.equalsIgnoreCase("fl")) {
							strValue = MD5.encode(strValue.toLowerCase());
						} else if (strEncoder.equalsIgnoreCase("fu")) {
							strValue = MD5.encode(strValue.toUpperCase());
						} else {
							throw new RuntimeException("Unsupported data encoder: " + strEncoder);
						}
					}
					
					ps.setString(i + 1, strValue);
					break;
				}
				case _date: {
					String strValue = (String) objValue;
					if (strValue.length() == 0) {
						ps.setNull(i + 1, java.sql.Types.TIMESTAMP);
					} else {
						ps.setString(i + 1, (String) objValue);
					}
					break;
				}
				case _time: {
					String strValue = (String) objValue;
					if (strValue.length() == 0) {
						ps.setNull(i + 1, java.sql.Types.TIMESTAMP);
					} else {
						ps.setString(i + 1, (String) objValue);
					}
					break;
				}
				case _datetime: {
					String strValue = (String) objValue;
					if (strValue.length() == 0) {
						ps.setNull(i + 1, java.sql.Types.TIMESTAMP);
					} else {
						ps.setString(i + 1, (String) objValue);
					}
					break;
				}
				case _boolean: {
					ps.setBoolean(i + 1, (Boolean) objValue);
					break;
				}
				case _bytes: {
					ps.setBytes(i + 1, (byte[]) objValue);
					break;
				}
				case _obj:{
					ps.setObject(i + 1, objValue);
					break;
				}
				default: {
					throw new SQLException("Unsupported type's object for " + strParaName + ": type:" + nType + ", value: " + objValue);
				}
				}
			}
		} catch (Exception e) {
			DBUtils.closeStatement(ps);
			throw new SQLException("prepareStatement exception: " + e.getMessage() + "\r\n" + sourceSQL, e);
		}
		
		formatSQL.setLength(0);
		formatSQL.append(sourceSQL);
		TransLog.callOnSQLStatement(logger,modelRequest, conn.hashCode(), sourceSQL);
		
		return ps;
	}
	
	/**
	 * 通过一个传入的数据库连接查询并输出第一条记录的第一个字段(含类型)
	 * 
	 * @param conn
	 * @param strSQL
	 * @param modelRequest
	 * @param modelResponse
	 * @return
	 * @throws Exception
	 */
	public JObject executeQueryFieldExt(Connection conn, String strSQL, Model modelRequest, HashSet<String> hsDecryptFieldNames) throws SQLException, IOException {
		// 准备JDBC语句
		StringBuilder strbFormatedSQL = new StringBuilder();
		PreparedStatement ps = prepareStatement(conn, strSQL, modelRequest, strbFormatedSQL);
		
		// 输出查询结果
		ResultSet rs = null;
		try {
			// 执行查询
			long lStartTime = System.currentTimeMillis();
			for (int i = 0; i < 3; i++) {
				try {
					rs = ps.executeQuery();
					break;
				} catch (Exception ce) {
					if (ce.toString().indexOf("CommunicationsException") >= 0) {
						continue;
					}
					throw ce;
				}
			}
			long lSQLTime = System.currentTimeMillis() - lStartTime;
			TransLog.callOnSQLExecuted(logger,modelRequest, conn.hashCode(), strbFormatedSQL.toString(), lSQLTime);
			
			ResultSetMetaData meta = rs.getMetaData();
			String[] strsFieldName = new String[1];
			int[] nsFieldType = new int[1];
			int[] nsPrecision = new int[1];
			int[] nsScale = new int[1];
			for (int i = 0; i < strsFieldName.length; i++) {
				strsFieldName[i] = meta.getColumnLabel(i + 1);
				nsFieldType[i] = meta.getColumnType(i + 1);
				nsPrecision[i] = meta.getPrecision(i + 1);
				nsScale[i] = meta.getScale(i + 1);
			}
			
			JObject objExt = RecordUtils.readField(rs, strsFieldName, nsFieldType, nsPrecision, nsScale);
			return objExt;
		} catch (SQLException e) {
			TransLog.onException(logger,"executeQueryField Exception: " + strSQL, modelRequest, e);
			throw e;
		} finally {
			DBUtils.closeResultSet(rs);
			DBUtils.closeStatement(ps);
		}
	}
	
	/**
	 * 通过一个传入的数据库连接查询并输出第一条记录
	 * 
	 * @param conn
	 * @param strSQL
	 * @param modelRequest
	 * @param modelResponse
	 * @return
	 * @throws Exception
	 */
	public int executeQueryRecord(Connection conn, String strSQL, Model modelRequest, Model modelResponse, HashSet<String> hsDecryptFieldNames) throws SQLException, IOException {
		// 准备JDBC语句
		StringBuilder strbFormatedSQL = new StringBuilder();
		PreparedStatement ps = prepareStatement(conn, strSQL, modelRequest, strbFormatedSQL);
		
		// 输出查询结果
		ResultSet rs = null;
		try {
			// 执行查询
			long lStartTime = System.currentTimeMillis();
			for (int i = 0; i < 3; i++) {
				try {
					rs = ps.executeQuery();
					break;
				} catch (Exception ce) {
					if (ce.toString().indexOf("CommunicationsException") >= 0) {
						continue;
					}
					throw ce;
				}
			}
			long lSQLTime = System.currentTimeMillis() - lStartTime;
			TransLog.callOnSQLExecuted(logger,modelRequest, conn.hashCode(), strbFormatedSQL.toString(), lSQLTime);
			
			ResultSetMetaData meta = rs.getMetaData();
			String[] strsFieldName = new String[meta.getColumnCount()];
			int[] nsFieldType = new int[strsFieldName.length];
			int[] nsPrecision = new int[strsFieldName.length];
			int[] nsScale = new int[strsFieldName.length];
			for (int i = 0; i < strsFieldName.length; i++) {
				strsFieldName[i] = meta.getColumnLabel(i + 1);
				nsFieldType[i] = meta.getColumnType(i + 1);
				nsPrecision[i] = meta.getPrecision(i + 1);
				nsScale[i] = meta.getScale(i + 1);
			}
			// 读取记录信息
			return RecordUtils.readRecord(rs, strsFieldName, nsFieldType, nsPrecision, nsScale, hsDecryptFieldNames,this.aes, modelResponse);
		} catch (SQLException e) {
			TransLog.onException(logger,"executeQueryRecord Exception: " + strSQL, modelRequest, e);
			throw e;
		} finally {
			DBUtils.closeResultSet(rs);
			DBUtils.closeStatement(ps);
		}
	}
	
	/**
	 * 通过一个传入的数据库连接查询并输出所有记录
	 * @param conn
	 * @param strSQL
	 * @param modelRequest
	 * @param hsEncrypeFieldNames
	 * @param modelsRecordSet
	 * @return
	 * @throws SQLException
	 * @throws IOException
	 */
	public int executeQueryRecordSet(Connection conn, String strSQL, Model modelRequest, HashSet<String> hsEncrypeFieldNames, Models modelsRecordSet) throws SQLException, IOException {
		// 准备JDBC语句
		StringBuilder strbFormatedSQL = new StringBuilder();
		PreparedStatement ps = prepareStatement(conn, strSQL, modelRequest, strbFormatedSQL);
		
		ResultSet rs = null;
		try {
			long lStartTime = System.currentTimeMillis();
			for (int i = 0; i < 3; i++) {
				try {
					rs = ps.executeQuery();// 执行查询
					break;
				} catch (Exception ce) {
					if (ce.toString().indexOf("CommunicationsException") >= 0) {
						continue;
					}
					throw ce;
				}
			}
			long lSQLTime = System.currentTimeMillis() - lStartTime;
			TransLog.callOnSQLExecuted(logger,modelRequest, conn.hashCode(), strbFormatedSQL.toString(), lSQLTime);
			
			// 读取Meta信息
			ResultSetMetaData meta = rs.getMetaData();
			String[] strsFieldName = new String[meta.getColumnCount()];
			int[] nsFieldType = new int[strsFieldName.length];
			int[] nsPrecision = new int[strsFieldName.length];
			int[] nsScale = new int[strsFieldName.length];
			for (int i = 0; i < strsFieldName.length; i++) {
				strsFieldName[i] = meta.getColumnLabel(i + 1);
				nsFieldType[i] = meta.getColumnType(i + 1);
				nsPrecision[i] = meta.getPrecision(i + 1);
				nsScale[i] = meta.getScale(i + 1);
			}
			
			// 读取记录
			ArrayList<Model> alRecord = new ArrayList<Model>();
			while (true) {
				// 读取记录信息
				Model modelRecord = RecordUtils.readRecord(rs, strsFieldName, nsFieldType, nsPrecision, nsScale,hsEncrypeFieldNames,this.aes);
				if (modelRecord == null) {
					break;
				}
				alRecord.add(modelRecord);
			}
			
			// 输出记录
			Model[] modelsRecord = new Model[alRecord.size()];
			for (int i = 0; i < modelsRecord.length; i++) {
				modelsRecord[i] = (Model) alRecord.get(i);
			}
			modelsRecordSet.setValue(modelsRecord);
			
			return modelsRecord.length;
		} catch (SQLException e) {
			TransLog.onException(logger,"executeQueryRecordSet Exception: " + strSQL, modelRequest, e);
			throw e;
		} finally {
			DBUtils.closeResultSet(rs);
			DBUtils.closeStatement(ps);
		}
	}
	
	/**
	 * 执行数据库更新语句
	 * @param conn
	 * @param strSQL
	 * @param modelRequest
	 * @return
	 * @throws SQLException
	 */
	public int executeUpdate(Connection conn, String sourceSQL, Model modelRequest) throws SQLException {
		// 准备JDBC语句
		StringBuilder formatSQL = new StringBuilder();
		PreparedStatement ps = prepareStatement(conn, sourceSQL, modelRequest, formatSQL);
		
		try {
			long startTime = System.currentTimeMillis();
			int nCount = 0;
			for (int i = 0; i < 3; i++) {
				try {
					nCount = ps.executeUpdate();// 执行更新
					break;
				} catch (Exception ce) {
					if (ce.toString().indexOf("CommunicationsException") >= 0) {
						continue;
					}
					throw ce;
				}
			}
			long transTime = System.currentTimeMillis() - startTime;
			TransLog.callOnSQLExecuted(logger,modelRequest, conn.hashCode(), formatSQL.toString(), transTime);
			return nCount;
		} catch (SQLException e) {
			TransLog.onException(logger,"executeUpdate Exception: " + sourceSQL, modelRequest, e);
			throw e;
		} finally {
			DBUtils.closeStatement(ps);
		}
	}
	
	
	
	// ----------------------------------------db----------------------------------------
	/**
	 * 打开数据库
	 */
	public synchronized Result open() {
		if (ds != null) {
			return Result.OK;
		}
		
		String strEnvPassword = Utility.getEnvValue(this.strPassword);
		
		HikariConfig config = new HikariConfig();
		config.setConnectionTimeout(30000L);// 连接超时时间-毫秒
		// config.setAutoCommit(false);
		config.setDriverClassName(this.strDriver);
		config.setJdbcUrl(DatabaseUtils.getRealURIByEnv(this.strURI));
		config.setPassword(strEnvPassword);
		config.setUsername(this.strUserName);
		config.setMaximumPoolSize(this.nMaxConnectionCount);
		config.setMinimumIdle(this.nMinConnectionCount);
		config.setAllowPoolSuspension(true);
		config.setPoolName(this.dataGroupId);
		
		if (strURI.indexOf("mysql") >= 0) {
			config.setConnectionTestQuery("select 1");
			config.setConnectionInitSql("select 1");
		} else if (strURI.indexOf("oracle") >= 0) {
			config.setConnectionTestQuery("select 1 from dual");
			config.setConnectionInitSql("select 1 from dual");
		} else if (strURI.indexOf("sqlserver") >= 0 || strDriver.indexOf("jtds") >= 0) {
			config.setConnectionTestQuery("select 1");
			config.setConnectionInitSql("select 1");
		}
		ds = new HikariDataSource(config);
		
		// ds=new BasicDataSource();
		// ds.setDriverClassName(this.strDriver);
		// ds.setUsername(this.strUserName);
		// ds.setPassword(strEnvPassword);
		// ds.setUrl(this.getRealURI(this.strURI));
		// ds.setInitialSize(this.nMinConnectionCount);
		// ds.setMaxActive(this.nMaxConnectionCount);
		// ds.setMaxIdle(this.nMaxIdleConnectionCount);
		// ds.setMinIdle(this.nMinConnectionCount);
		// ds.setMaxWait(this.nMaxWaitTimeForIdleConnection);// 最大等待空闲连接的时间
		// ds.setTimeBetweenEvictionRunsMillis(this.nCheckIdleIntervalMS);//在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位
		// ds.setNumTestsPerEvictionRun(this.nCheckIdleConnCountOnce);//在每次空闲连接回收器线程(如果有)运行时检查的连接数量
		// ds.setMinEvictableIdleTimeMillis(this.nMaxConnIdleTimeMS);//连接在池中保持空闲而不被空闲连接回收器线程(如果有)回收的最小时间值，单位毫秒
		// ds.setTestWhileIdle(true);
		// ds.setTestOnBorrow(true);
		// if(strURI.indexOf("mysql")>=0)
		// {
		// ds.setValidationQuery("select 1");
		// }
		// else if(strURI.indexOf("oracle")>=0)
		// {
		// ds.setValidationQuery("select 1 from dual");
		// }
		// else if(strURI.indexOf("sqlserver")>=0 ||
		// strDriver.indexOf("jtds")>=0)
		// {
		// ds.setValidationQuery("select 1");
		// }
		// ds.setPoolPreparedStatements(true);
		// ds.setRemoveAbandoned(this.bRemoveAbandoned);
		// ds.setRemoveAbandonedTimeout(this.nTimeout);
		// ds.setLogAbandoned(true);
		
		// 打开连接
		try {
			logger.info("Opening database: " + ds.getJdbcUrl());
			Connection conn = ds.getConnection();
			DBUtils.closeConnection(conn);
		} catch (Exception e) {
			TransLog.onException(logger,"Open database error: " + e.getMessage(), e);
			
			Result ret = Result.valueOf(-1, e.getMessage(), "System.Error");
			ret.setThrowable(e);
			return ret;
			
		}
		
		return Result.OK;
	}
	
	/**
	 * 关闭数据库
	 * 
	 */
	public synchronized void close() {
		if (ds != null) {
			try {
				ds.close();
			} catch (Exception e) {
			}
			ds = null;
		}
		
		// synchronized(this.hmAnalyzedSQL)
		// {
		// this.hmAnalyzedSQL.clear();
		// }
	}
	
	/**
	 * 获取一个数据库连接
	 * @return
	 * @throws SQLException
	 */
	public Connection getConnection() throws SQLException {
		Result ret = this.open();
		if (ret.getCode() != 0) {
			return null;
		}
		
		Connection conn = null;
		long lStartTime = System.currentTimeMillis();
		try {
			int nMaxCount = 3;
			for (int i = 0; i < nMaxCount; i++) {// CommunicationsException最多试N次
				try {
					conn = this.ds.getConnection();
					break;
				} catch (Exception e) {
					if (i >= nMaxCount - 1) {
						throw e;
					}
					continue;
				}
			}
		} finally {
			long lDelay = System.currentTimeMillis() - lStartTime;
			
			if (lDelay >= 100) {
				logger.warn("DataEngine.getConnection time: " + lDelay + "ms");
			}
		}
		return conn;
	}
	
	// --------------------------------------get set-----------------------------------
	public void setDataGroupId(String id) {
		this.dataGroupId = id;
	}
	
	public void setDriver(String strDriver) {
		this.strDriver = strDriver;
	}
	
	public String getDriver() {
		return this.strDriver;
	}
	
	public void setURI(String strURI) {
		this.strURI = strURI;
	}
	
	public String getURI() {
		return this.strURI;
	}
	
	public Properties getProperties() {
		return properties;
	}
	
	public void setProperties(Properties properties) {
		this.properties = properties;
	}
	
	public String getUserName() {
		return strUserName;
	}
	
	public void setUserName(String strUserName) {
		this.strUserName = strUserName;
	}
	
	public String getPassword() {
		return strPassword;
	}
	
	public void setPassword(String strPassword) {
		this.strPassword = strPassword;
	}
	
	public void setMinConnectionCount(int nMinConnectionCount) {
		this.nMinConnectionCount = nMinConnectionCount;
	}
	
	public int getMinConnectionCount() {
		return this.nMinConnectionCount;
	}
	
	public void setMaxConnectionCount(int nMaxConnectionCount) {
		this.nMaxConnectionCount = nMaxConnectionCount;
	}
	
	public int getMaxConnectionCount() {
		return this.nMaxConnectionCount;
	}
	
	public void setTimeout(int nTimeout) {
		this.nTimeout = nTimeout;
	}
	
	public int getTimeout() {
		return this.nTimeout;
	}
	
	public int getMaxIdleConnectionCount() {
		return this.nMaxIdleConnectionCount;
	}
	
	public void setMaxIdleConnectionCount(int nMaxIdleConnectionCount) {
		this.nMaxIdleConnectionCount = nMaxIdleConnectionCount;
	}
	
	public int getMaxWaitTimeForIdleConnection() {
		return this.nMaxWaitTimeForIdleConnection;
	}
	
	public void setMaxWaitTimeForIdleConnection(int nMaxWaitTimeForIdleConnection) {
		this.nMaxWaitTimeForIdleConnection = nMaxWaitTimeForIdleConnection;
	}
	
	public int getMaxConnIdleTimeMS() {
		return this.nMaxConnIdleTimeMS;
	}
	
	public void setMaxConnIdleTimeMS(int nMaxConnIdleTimeMS) {
		this.nMaxConnIdleTimeMS = nMaxConnIdleTimeMS;
	}
	
	public int getCheckIdleIntervalMS() {
		return this.nCheckIdleIntervalMS;
	}
	
	public void setCheckIdleIntervalMS(int nCheckIdleIntervalMS) {
		this.nCheckIdleIntervalMS = nCheckIdleIntervalMS;
	}
	
	public int getCheckIdleConnCountOnce() {
		return this.nCheckIdleConnCountOnce;
	}
	
	public void setCheckIdleConnCountOnce(int nCheckIdleConnCountOnce) {
		this.nCheckIdleConnCountOnce = nCheckIdleConnCountOnce;
	}
	
	public boolean isOpened() {
		if (ds == null) {
			return false;
		} else {
			return true;
		}
	}
	
	public void setLoadLevel(int nLoadlevel) {
		this.nLoadLevel = nLoadlevel;
	}
	
	public int getLoadLevel() {
		return this.nLoadLevel;
	}
	
	public void setRemoveAbandoned(boolean bRemoveAbandoned) {
		this.bRemoveAbandoned = bRemoveAbandoned;
	}
	
	public void setDataKeyIV(String strKeyIV) {
		if (strKeyIV == null || strKeyIV.length() == 0) {
			return;
		}
		String strEnvKeyIV = Utility.getEnvValue(strKeyIV);
		String strDataKey;
		String strDataIV;
		String[] strsKeyItem = Utility.splitString(strEnvKeyIV, '|');
		if (strsKeyItem.length == 1) {
			strDataKey = strsKeyItem[0];
			strDataIV = strsKeyItem[0];
		} else if (strsKeyItem.length == 2) {
			strDataKey = strsKeyItem[0];
			strDataIV = strsKeyItem[1];
		} else {
			throw new RuntimeException("Invalid encryption: " + strKeyIV);
		}
		this.aes = new AES();
		this.aes.init(strDataKey, strDataIV);
	}
	
//	 public static void main(String[] args) {
//		 DataEngine dataEngine = new DataEngine();
//		
//		 String dd = dataEngine.getRealURI(
//		 "jdbc:mysql://192.168.1.188:3306/shop?serverTimezone=GMT&Unicode=true&characterEncoding=utf8");
//		 System.out.println(dd);
//		 Model modelRequest = new Model();
//		 modelRequest.set("strName", "qqq");
//		
//		 System.out.println(com.gavin.plugin.database.help.Condition.checkCondition("{strName}", "EXIST", "NULL",
//		 0, "string", modelRequest));
//	 }
}
